from ipmininet.iptopo import IPTopo
import logging
import os
from ipmininet.router.config import RouterConfig, Openr
from ipmininet.ipnet import IPNet
from ipmininet.cli import IPCLI
from six.moves import range
from ipmininet.topologydb import TopologyDB


logger = logging.getLogger(__name__)


class OpenrConfig(RouterConfig):
    """A simple config with only a OpenR daemon"""

    def __init__(self, node, *args, **kwargs):
        defaults = {"enable_v4": True, "ifname_prefix": "", "iface_regex_exclude": "l*"}
        defaults = {"enable_v4": True}
        super().__init__(node, daemons=((Openr, defaults),), *args, **kwargs)


class FatTree(IPTopo):
    CoreSwitchList = []
    AggSwitchList = []
    EdgeSwitchList = []
    HostList = []

    def __init__(self, k):
        " Create Fat Tree topo."
        self.pod = k
        self.iCoreLayerSwitch = (k / 2) ** 2
        self.iAggLayerSwitch = k * k / 2
        self.iEdgeLayerSwitch = k * k / 2
        self.density = k / 2
        self.iHost = self.iEdgeLayerSwitch * self.density

        self.bw_c2a = 0.2
        self.bw_a2e = 0.1
        self.bw_h2a = 0.05

        # Init Topo
        IPTopo.__init__(self)

        self.createTopo()
        logger.debug("Finished topology creation!")

        self.createLink(bw_c2a=self.bw_c2a,
                        bw_a2e=self.bw_a2e,
                        bw_h2a=self.bw_h2a)
        logger.debug("Finished adding links!")

    #    self.set_ovs_protocol_13()
    #    logger.debug("OF is set to version 1.3!")

    def createTopo(self):
        self.createCoreLayerSwitch(self.iCoreLayerSwitch)
        self.createAggLayerSwitch(self.iAggLayerSwitch)
        self.createEdgeLayerSwitch(self.iEdgeLayerSwitch)
        self.createHost(self.iHost)

    """
    Create Switch and Host
    """

    def _addSwitch(self, number, level, switch_list):
        number = int(number)
        for x in range(1, number + 1):
            PREFIX = str(level) + "00"
            if x >= int(10):
                PREFIX = str(level) + "0"
            switch_list.append(self.addRouter('r' + PREFIX + str(x), config=OpenrConfig,
                                              privateDirs=['/tmp', '/var/log']))

    def createCoreLayerSwitch(self, NUMBER):
        logger.debug("Create Core Layer")
        self._addSwitch(NUMBER, 1, self.CoreSwitchList)

    def createAggLayerSwitch(self, NUMBER):
        logger.debug("Create Agg Layer")
        self._addSwitch(NUMBER, 2, self.AggSwitchList)

    def createEdgeLayerSwitch(self, NUMBER):
        logger.debug("Create Edge Layer")
        self._addSwitch(NUMBER, 3, self.EdgeSwitchList)

    def createHost(self, NUMBER):
        logger.debug("Create Host")
        NUMBER = int(NUMBER)
        for x in range(1, NUMBER + 1):
            PREFIX = "h00"
            if x >= int(10):
                PREFIX = "h0"
            elif x >= int(100):
                PREFIX = "h"
            self.HostList.append(self.addHost(PREFIX + str(x)))

    """
    Add Link
    """

    def createLink(self, bw_c2a=0.2, bw_a2e=0.1, bw_h2a=0.5):
        logger.debug("Add link Core to Agg.")
        end = self.pod / 2
        end = int(end)
        for x in range(0, int(self.iAggLayerSwitch), end):
            for i in range(0, end):
                for j in range(0, end):
                    linkopts = dict()  # dict(bw=bw_c2a)
                    self.addLink(
                        self.CoreSwitchList[i * end + j],
                        self.AggSwitchList[x + i],
                        **linkopts)

        logger.debug("Add link Agg to Edge.")
        for x in range(0, int(self.iAggLayerSwitch), end):
            for i in range(0, end):
                for j in range(0, end):
                    linkopts = dict()  # dict(bw=bw_a2e)
                    self.addLink(
                        self.AggSwitchList[x + i], self.EdgeSwitchList[x + j],
                        **linkopts)

        logger.debug("Add link Edge to Host.")
        for x in range(0, int(self.iEdgeLayerSwitch)):
            for i in range(0, int(self.density)):
                linkopts = dict()  # dict(bw=bw_h2a)
                self.addLink(
                    self.EdgeSwitchList[x],
                    self.HostList[int(self.density * x + i)],
                    **linkopts)


net = IPNet(topo=FatTree(8), max_v4_prefixlen=25)

try:
    db = TopologyDB(net=net)
    db_path = "/tmp/topologydb.json"
    db.save(db_path)
    net.start()
    IPCLI(net)
finally:
    net.stop()
